分类
联系方式
  1. 新浪微博
  2. E-mail

Qt6 Example WebEngine Content Manipulation

介绍

Qt6 出了,使用 C++17,因此尝鲜一下。对 Qt 的 QWebEngine 很感兴趣,跑了一下使用 JQuery 的网页浏览 Demo。Qt 整体开发体验很不错,适合写一些严肃有深度的桌面程序。

CMake

CMake 内容如下:

cmake_minimum_required(VERSION 3.5)

project(WebEngineDemoManipulate VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt6 COMPONENTS Core)
find_package(Qt6 COMPONENTS Gui)
find_package(Qt6 COMPONENTS WebEngineWidgets)
find_package(Qt6 COMPONENTS Positioning REQUIRED)
find_package(Qt6 COMPONENTS PrintSupport)


set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
)

qt_add_executable(WebEngineDemoManipulate
    MANUAL_FINALIZATION
    ${PROJECT_SOURCES}
    jquery.qrc
)

target_link_libraries(WebEngineDemoManipulate PRIVATE
    Qt::Core
    Qt::Gui
    Qt::WebEngineWidgets
    Qt::Positioning)

set_target_properties(WebEngineDemoManipulate PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(WebEngineDemoManipulate)
endif()
  1. 所使用到的 Qt Module,需要先 find_package,然后再放入到 link 中。
  2. WebEngine 对应的组件是 WebEngineWidgets,它还有依赖组件 Positioning 和 PrintSupport。其中 WebEngineWidgets 和 Positioning 都是附加模块,需要单独安装
  3. 在 Windows 下,Qt WebEngine 只支持使用 MSVS2019 构建,MinGW 8.1.0 是不包含这个模块的。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

QT_BEGIN_NAMESPACE
class QWebEngineView;
class QLineEdit;
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(const QUrl& url);
    ~MainWindow();

protected slots:
    void adjustLocation();
    void changeLocation();
    void adjustTitle();
    void setProgress(int p);
    void finishLoad(bool);

    void viewSource();

    void highlightAllLinks();
    void rotateImages(bool invert);
    void removeGifImages();
    void removeInlineFrames();
    void removeObjectElements();
    void removeEmbeddedElements();

private:
    QString jQuery;
    QWebEngineView *view;
    QLineEdit *locationEdit;
    QAction *rotateAction;
    int progress;
};
#endif // MAINWINDOW_H

mainwindow.cpp

构造方法:

#include <QtWidgets>
#include <QtWebEngineWidgets>
#include <QDebug>
#include "mainwindow.h"

MainWindow::MainWindow(const QUrl& url) {
    setAttribute(Qt::WA_DeleteOnClose, true);
    progress = 0;

    QFile file;
    file.setFileName(":/jquery.min.js");
    file.open(QIODevice::ReadOnly);

    jQuery = file.readAll();
    jQuery.append("\nvar qt = { 'jQuery': jQuery.noConflict(true) };");

    file.close();

    view = new QWebEngineView(this);
    view->load(url);

    connect(view, &QWebEngineView::loadFinished, this, &MainWindow::adjustLocation);
    connect(view, &QWebEngineView::titleChanged, this, &MainWindow::adjustTitle);
    connect(view, &QWebEngineView::loadProgress, this, &MainWindow::setProgress);
    connect(view, &QWebEngineView::loadFinished, this, &MainWindow::finishLoad);

    locationEdit = new QLineEdit(this);
    locationEdit->setSizePolicy(
        QSizePolicy::Expanding, locationEdit->sizePolicy().verticalPolicy());
    connect(locationEdit, &QLineEdit::returnPressed, this, &MainWindow::changeLocation);

    QToolBar *toolBar = addToolBar(tr("Navigation"));
    toolBar->addAction(view->pageAction(QWebEnginePage::Back));
    toolBar->addAction(view->pageAction(QWebEnginePage::Forward));
    toolBar->addAction(view->pageAction(QWebEnginePage::Reload));
    toolBar->addAction(view->pageAction(QWebEnginePage::Stop));
    toolBar->addWidget(locationEdit);

    QMenu *viewMenu = menuBar()->addMenu(tr("&Tools"));

    QAction *viewSourceActoin = new QAction(tr("Page Source"), this);
    connect(viewSourceActoin, &QAction::triggered, this, &MainWindow::viewSource);
    viewMenu->addAction(viewSourceActoin);

    viewMenu->addAction(tr("Highlight all links"), this, &MainWindow::highlightAllLinks);

    rotateAction = new QAction(this);
    rotateAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView));
    rotateAction->setCheckable(true);
    rotateAction->setText(tr("Turn Images upside and down"));
    connect(rotateAction, &QAction::toggled, this, &MainWindow::rotateImages);
    viewMenu->addAction(rotateAction);

    viewMenu->addAction(tr("Remove GIF Images"), this, &MainWindow::removeGifImages);
    viewMenu->addAction(tr("Remove all inline frames"), this, &MainWindow::removeInlineFrames);
    viewMenu->addAction(tr("Remove all object elements"), this, &MainWindow::removeEmbeddedElements);

    setCentralWidget(view);
}
  1. qrc 资源访问方式

加载完成执行 JS(JQuery):

void MainWindow::finishLoad(bool) {
    progress = 100;
    adjustTitle();
    view->page()->runJavaScript(jQuery);
}

弹出新窗口查看源码:

void MainWindow::viewSource() {
    QTextEdit *textEdit = new QTextEdit(nullptr);
    textEdit->setAttribute(Qt::WA_DeleteOnClose);
    textEdit->adjustSize();
    textEdit->move(this->geometry().center() - textEdit->rect().center());
    textEdit->show();

//    view->page()->toHtml([textEdit](const QString & html) {
//        textEdit->setPlainText(html);
//    });
    textEdit->setPlainText(jQuery);
}

将所有超链接高亮展示:

void MainWindow::highlightAllLinks() {
    QString code = QStringLiteral("qt.jQuery('a').each(function() {qt.jQuery(this).css('background-color', 'yellow') })");
    view->page()->runJavaScript(code, [](const QVariant & data) {
        qInfo() << data;
    });
}

添加资源文件

工程中使用到了 JQuery,将 jquery.min.js 放到项目根目录。

创建新文件 jquary.qrc,选择 Qt Resource,这是一个资源路径,前缀输入 /,再路径中添加 jquery.min.js。

将资源文件 jquary.qrc 添加到 cmake 当中。

IDE 使用技巧

  1. 切换头文件和源码文件 Shift+F2
  2. 切主题,Qt Creator Dark 很好看
  3. 字体 Cascadia Code SemiLight 很好看(尤其是斜体,有种手写的韵味,还有 -> 常用连写都没问题)
  4. 保存代码自动 Format,去帮助 Help 中装 Beautifier 插件,然后二进制连接到 Artistic Style,选择 Use customized style,输入:--style=google -p

网络资源

Example 地址

代码